<?php
	/* Functions in this file */
	/**************************/

	// DeleteNoteArrayContents()
	// GetMFCClassName()
	// GetMFCClassSchema()
	// GetMusicNotationOffset()
	// GetName()
	// GetNoteRange($capo)
	// GetNoteText($string)
	// GetSpelling()
	// GetStringCount()
	// IsOpenStringNote($note)
	// IsSameTuning(&$tuning)
	// IsValid()
	// IsValidMusicNotationOffset($musicNotationOffset)
	// IsValidString($string)
	// IsValidStringCount($stringCount)
	// SetMusicNotationOffset($musicNotationOffset)
	// SetName($name)
	// SetSharps($set)
	// SetTuningFromString($string)
	// UsesSharps()
?>
<?php
	 
	 
	class Tuning {
		 
		 
		const DEFAULT_NAME = "";
		const DEFAULT_DATA = 0;
		const MIN_MUSIC_NOTATION_OFFSET = -12;
		const MAX_MUSIC_NOTATION_OFFSET = 12;
		const MIN_STRING_COUNT = 3;
		const MAX_STRING_COUNT = 7;
		 
		 
		const sharpsMask = 0x00000001;
		const musicNotationOffsetMask = 0x000000fe;
		const musicNotationOffsetSignMask = 0x00000080;
		const musicNotationOffsetValueMask = 0x0000007e;
		const notUsed = 0x000000ff;
		 
		 
		protected $m_name = self::DEFAULT_NAME;
		protected $m_data = self::DEFAULT_DATA;
		protected $m_noteArray = array ();
		 
		 
		 
		// MFC Class Functions
		 
		 
		function GetMFCClassName() {
			return "CTuning";
		}
		 
		 
		function GetMFCClassSchema() {
			return 1;
		}
		 
		// Name Functions
		 
		 
		 
		function SetName($name) {
			if (!$name != NULL) return 0;
			$this->m_name = $name;
			 return 1;
		}
		 
		 
		function GetName() {
			return ($this->m_name);
		}
		 
		// Music Notation Offset Functions
		 
		 
		 
		function IsValidMusicNotationOffset($musicNotationOffset) {
			return (($musicNotationOffset >= self::MIN_MUSIC_NOTATION_OFFSET) && (($musicNotationOffset <= self::MAX_MUSIC_NOTATION_OFFSET)));
		}
		 
		 
		 
		function UsesSharps() {
			return (($this->m_data & self::sharpsMask) == self::sharpsMask);
		}
		 
		// String Functions
		 
		 
		 
		function IsValidStringCount($stringCount) {
			return (($stringCount >= self::MIN_STRING_COUNT) && ($stringCount <= self::MAX_STRING_COUNT));
		}
		 
		 
		 
		function IsValidString($string) {
			return (($string >= 0) && ($string < $this->GetStringCount()));
		}
		 
		 
		function GetStringCount() {
			return sizeof($this->m_noteArray);
		}
		 
		 
		// Operations
		 
		 
		function IsValid() {
			return ($this->IsValidStringCount($this->GetStringCount()));
		}
		 
		// Constructors/Destructors
		 
		 
		 
		function Tuning($name = NULL, $musicNotationOffset = NULL, $sharps = NULL, $note1 = NULL, $note2 = NULL, $note3 = NULL, $note4 = NULL, $note5 = NULL, $note6 = NULL, $note7 = NULL) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			if (!$name != NULL) return 0;
			if (!$this->IsValidMusicNotationOffset($musicNotationOffset)) return 0;
			 
			$this->SetSharps($sharps);
			$this->SetMusicNotationOffset($musicNotationOffset);
			$this->AddTuningNotes($note1, $note2, $note3, $note4, $note5, $note6, $note7);
		}
		 
		 
		
		// Serialize Functions
		  
		function DoSerialize(&$stream){
		 
		
			WRITE_CSTRING ($stream,$this->m_name);

			WRITE_BYTE ($stream,$this->m_data);

			// Write the $string count as a byte
			$stringCount = $this->GetStringCount();
			WRITE_BYTE ($stream,$stringCount);

			// Write each $note
			$i = 0;
			for (; $i < $stringCount; $i++) {
				WRITE_BYTE ($stream,$this->m_noteArray[$i]);
			}
			return 1;
		}
		 
		  
		 
		function DoDeserialize(&$stream){
		 
		
			$this->m_name = READ_CSTRING ($stream);
		
			$this->m_data = READ_BYTE ($stream);
		
		 
			$this->DeleteNoteArrayContents();
		 
			// Get number of $notes, then the $notes themselves
			$stringCount = READ_BYTE ($stream);
		
			$i = 0;
			for (; $i < $stringCount; $i++) {
		 
				$note = READ_BYTE ($stream);
		
				array_push($this->m_noteArray,$note);
			}
			
			// echo $this->GetStringCount() . "<br/>";
		
		
		}
		 
		
		 
		 
		function SetTuning($name, $musicNotationOffset, $sharps, $note1, $note2, $note3, $note4, $note5, $note6, $note7) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			if (!$this->SetName($name))
				return 0;
			$this->SetSharps($sharps);
			if (!$this->SetMusicNotationOffset($musicNotationOffset))
				return 0;
			return ($this->AddTuningNotes($note1, $note2, $note3, $note4, $note5, $note6, $note7));
		}
		 
		 
		 
		 
		function SetTuningFromString($string) {
			 
			 
			if ($string == NULL) return 0;
			 
			// Get the tuning name
			$name = explode(',', $string);
			 
			if (!$this->SetName($name[0]))
				return 0;
			 
			$sharps = $name[1];
			if ($sharps != 1)
				$sharps = 0;
			$this->SetSharps(($sharps != 0));
			 
			// Get the music notation offset
			$musicNotationOffset = $name[2];
			if (!$this->SetMusicNotationOffset($musicNotationOffset))
				return 0;
			 
			// Get the notes
			$notes = array();
			$i = 0;
			for (; $i < self::MAX_STRING_COUNT; $i++)
			$notes[$i] = self::notUsed;
			 
			$i = 3;
			for (; $i < 10; $i++) {
				 
				$notes[$i - 3] = $name[$i];
			}
			 
			return ($this->AddTuningNotes($notes[0], $notes[1], $notes[2], $notes[3], $notes[4], $notes[5], $notes[6]));
			 
			 
		}
		 
		 
		 
		function IsSameTuning(&$tuning) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			 
			$thisStringCount = $this->GetStringCount();
			$otherStringCount = $tuning->GetStringCount();
			 
			// $this->Tunings have a different number of $strings
			if ($thisStringCount != $otherStringCount)
				return 0;
			 
			// Check each $string for matching $notes
			$i = 0;
			for (; $i < $thisStringCount; $i++) {
				 
				if ($this->m_noteArray[$i] != $tuning->m_noteArray[$i])
					return 0;
			}
			 
			return 1;
		}
		 
		 
		 
		function IsSameTuningNotes($note1, $note2, $note3, $note4, $note5, $note6, $note7) {
			 
			//------Last Checked------//
			// - Dec 15, 2004
			$temp = new Tuning ();
			$temp->AddTuningNotes($note1, $note2, $note3, $note4, $note5, $note6, $note7);
			return ($this->IsSameTuning($temp));
		}
		 
		// Sharps Functions
		 
		 
		function SetSharps($set) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			$this->m_data &= ~self::sharpsMask;
			if ($set)
				$this->m_data |= self::sharpsMask;
		}
		 
		// Music Notation Offset Functions
		 
		 
		 
		function SetMusicNotationOffset($musicNotationOffset) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			if (!$this->IsValidMusicNotationOffset($musicNotationOffset)) return 0;
			 
			// Clear the current music notation offset
			$this->m_data &= ~self::musicNotationOffsetMask;
			 
			// Set the sign bit if the offset is negative
			if ($musicNotationOffset < 0)
				$this->m_data |= self::musicNotationOffsetSignMask;
			 
			// Set the music notation offset value
			$this->m_data |= (abs($musicNotationOffset) << 1);
			 
			return 1;
		}
		 
		 
		 
		function GetMusicNotationOffset() {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			$returnValue = (($this->m_data & self::musicNotationOffsetValueMask) >> 1);
			 
			// If the sign is $set, the value is negative
			if (($this->m_data & self::musicNotationOffsetSignMask) == self::musicNotationOffsetSignMask)
				$returnValue = $returnValue * -1;
			 
			return ($returnValue);
		}
		 
		// Note Functions
		 
		 
		 
		 
		function SetNote($string, $note) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			if (!$this->IsValidString($string)) return 0;
			if (!wxIsValidMidiNote($note)) return 0;
			$this->m_noteArray[$string] = $note;
			return 1;
		}
		 
		 
		 
		 
		 
		function GetNote($string, $includeMusicNotationOffset = 0) {
			 
			if (!$this->IsValidString($string)) return MIDI_NOTE_MIDDLE_C;
			 
			$returnValue = $this->m_noteArray[$string];
			 
			// Include the music notation offset
			if ($includeMusicNotationOffset)
				$returnValue = wxOffsetMidiNote($returnValue, $this->GetMusicNotationOffset());
			 
			return $returnValue;
			 
			 
		}
		 
		 
		 
		 
		function GetNoteText($string) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			if (!$this->IsValidString($string)) return "";
			return (wxGetMidiNoteText($this->m_noteArray[$string], $this->UsesSharps()));
		}
		 
		 
		 
		 
		function IsOpenStringNote($note) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			$i = 0;
			$nCount = $this->GetStringCount();
			for (; i < $nCount; $i++) {
				 
				if ($this->m_noteArray[$i] != self::notUsed) {
					 
					// Note matches a tuning $note; it's an open $string $note
					if ($this->m_noteArray[$i] == $note)
						return 1;
				}
			}
			return 0;
		}
		 
		 
		 
		 
		function GetNoteRange($capo) {
			 
			$returnValue = array(self::notUsed, 0);
			 
			// Loop through each tuning note and get the minimum and maximum notes for the string
			$i = 0;
			$stringCount = $this->GetStringCount();
			for (; $i < $stringCount; $i++) {
				if ($this->m_noteArray[$i] != self::notUsed) {
					$returnValue[0] = min($returnValue[0], $this->m_noteArray[$i] + $capo);
					$returnValue[1] = max($returnValue[1], $this->m_noteArray[$i] + $capo + 24);
					// Assume guitar has 24 frets
				}
			}
			return $returnValue;
			 
		}
		 
		 
		function AddTuningNotes($note1, $note2, $note3, $note4, $note5, $note6, $note7) {
			 
			//------Last Checked------//
			// - Dec 14, 2004
			if (!wxIsValidMidiNote($note1)) return 0;
			if (!wxIsValidMidiNote($note2)) return 0;
			if (!wxIsValidMidiNote($note3)) return 0;
			if (!wxIsValidMidiNote($note4) || ($note4 == self::notUsed)) return 0;
			if (!wxIsValidMidiNote($note5) || ($note5 == self::notUsed)) return 0;
			if (!wxIsValidMidiNote($note6) || ($note6 == self::notUsed)) return 0;
			if (!wxIsValidMidiNote($note7) || ($note7 == self::notUsed)) return 0;
			 
			$this->DeleteNoteArrayContents();
			 
			array_push($this->m_noteArray, $note1);
			array_push($this->m_noteArray, $note2);
			array_push($this->m_noteArray, $note3);
			 
			if ($note4 == self::notUsed)
				return 1;
			array_push($this->m_noteArray, $note4);
			 
			if ($note5 == self::notUsed)
				return 1;
			array_push($this->m_noteArray, $note5);
			 
			if ($note6 == self::notUsed)
				return 1;
			array_push($this->m_noteArray, $note6);
			 
			if ($note7 == self::notUsed)
				return 1;
			array_push($this->m_noteArray, $note7);
			 
			return 1;
		}
		 
		 
		function DeleteNoteArrayContents() {
			 
			//------Last Checked------//
			// - Jan 11, 2005
			$this->m_noteArray = array ();
		}
		 
		// Operations
		 
		 
		function GetSpelling() {
			 
			$returnValue = "";
			 
			$stringCount = $this->GetStringCount();
			 
			// Go from lowest to highest string
			$i = $stringCount;
			for (; $i > 0; $i--) {
				if ($i != $stringCount)
				$returnValue .= " ";
				$returnValue .= sprintf("%s", $this->GetNoteText($i - 1));
			}
			 
			return $returnValue;
			 
		}


		
		//MODIFIED by Ryan 28/06/2011
		function GetLetterAndNumber(){
			//Converter array
			$converter = array("F#"=>"Gb","C#"=>"Db","G#"=>"Ab","D#"=>"Eb",
								"A#"=>"Bb","E#"=>"Fb","B#"=>"Cb");
			$returnValue = "";
			$data = $this->m_noteArray;
			$stringCount = $this->GetStringCount();
			for ($i = 0; $i < $stringCount; $i++) {
				if ($i != 0){
					$returnValue .= " ";
				}
				$number = $data[$i];
				$k = -1;
				while($number > 12){
					$number -= 12;
					$k++;
				}
				//Kludgy here flipping the array, but it works
				if(in_array($this->GetNoteText($i),array_flip($converter))){
					$returnValue .= sprintf("%s%d",$converter[$this->GetNoteText($i)],$k+1);
				}else{
					$returnValue .= sprintf("%s%d",$this->GetNoteText($i),$k+1);
				}
			}
			return $returnValue;
		}
		 
		 
	}
	 
?>

